'''
Description: 
Author: notplus
Date: 2021-12-10 09:04:36
LastEditors: notplus
LastEditTime: 2021-12-14 18:56:34
FilePath: /dbscan_cluster.py

Copyright (c) 2021 notplus
'''

import pickle
import numpy as np
from pyproj import Transformer
import matplotlib.pyplot as plt
from sklearn import cluster
from sklearn.cluster import DBSCAN

import utils
from extra_stay_points import User, Trajectory, StayPoint

# pickle_filename = 'activity.pickle'
pickle_filename = 'activity_153.pickle'

with open(pickle_filename, 'rb') as f:
    users = pickle.load(f)

all_activity = []
for user in users:
    all_activity += (user.trajs.stay_points)

all_activity.sort(key=lambda act: act.lev_t - act.arv_t)

time_interval = []

for user in users:
    i = 0
    point_num = len(user.trajs.stay_points)
    distance_matrix = np.zeros((point_num, point_num))
    time_interval_matrix = np.zeros((point_num, point_num))

    for i in range(len(user.trajs.stay_points)-1):
        # if (user.trajs.stay_points[i+1].arv_t - user.trajs.stay_points[i].lev_t).total_seconds() == 0:
        #     print('000')
        time_interval.append(
            (user.trajs.stay_points[i+1].arv_t - user.trajs.stay_points[i].lev_t).total_seconds())

    print(np.mean(time_interval) / 3600)

    for i in range(point_num):
        for j in range(i + 1, point_num):
            distance_matrix[j][i] = distance_matrix[i][j] = utils.compute_dist(user.trajs.stay_points[i], user.trajs.stay_points[j])

    db = DBSCAN(eps=15, metric='precomputed', min_samples=1, n_jobs=-1).fit(distance_matrix)
    labels = db.labels_
    n_clusters_ = len(set(labels)) - (1 if -1 in labels else 0)

    c = {}

    for i in range(n_clusters_):
        c[i] = []

    for i in range(len(labels)):
        c[labels[i]].append(i) 

    cluster_twice = {}
    last_num_label = 0

    for ii in range(len(c)):
        point_num_c = len(c[ii])
        time_interval_c = []
        time_interval_matrix_c = np.zeros((point_num_c, point_num_c))
        
        for i in range(point_num_c):
            for j in range(i + 1, point_num_c):
                arv_t = (user.trajs.stay_points[c[ii][j]].arv_t - user.trajs.stay_points[c[ii][j]].arv_t.replace(hour=0, minute=0, second=0, microsecond=0)).total_seconds() / 3600
                lev_t = (user.trajs.stay_points[c[ii][i]].arv_t - user.trajs.stay_points[c[ii][i]].arv_t.replace(hour=0, minute=0, second=0, microsecond=0)).total_seconds() / 3600
                
                time_interval_matrix_c[j][i] = time_interval_matrix_c[i][j] = abs(lev_t - arv_t)

        
        db = DBSCAN(eps=np.mean(time_interval) / 3600, metric='precomputed',
                min_samples=1, n_jobs=-1).fit(time_interval_matrix_c)
        labels = db.labels_

        n_clusters_ = len(set(labels)) - (1 if -1 in labels else 0)
        print('num cluster: %d' % (n_clusters_))

        for j in range(n_clusters_):
            cluster_twice[j+last_num_label] = []

        for j in range(len(labels)):
            cluster_twice[labels[j]+last_num_label].append(c[ii][j])

        last_num_label += n_clusters_


        
    label_sort = sorted(cluster_twice, key=lambda key : len(cluster_twice[key]))[::-1]
    
    # max_label = max(c, key=lambda key : len(c[key]))


    fig = plt.figure()
    ax = fig.add_subplot(111, projection='3d')
    for j in range(5):
        x = []
        y = []
        z = []
        
        for i in cluster_twice[label_sort[j]]:
            transformer = Transformer.from_crs("epsg:4326", "epsg:32650") 
            xt, yt = transformer.transform(user.trajs.stay_points[i].lat, user.trajs.stay_points[i].lng)
            x.append(xt)
            y.append(yt)
            z.append((user.trajs.stay_points[i].arv_t - user.trajs.stay_points[i].arv_t.replace(hour=0, minute=0, second=0, microsecond=0)).total_seconds() / 3600)
    
        ax.scatter(x, y, z, marker='^')

    for j in range(5):
        fig = plt.figure()
        ax = fig.add_subplot(111, projection='3d')

        x = []
        y = []
        z = []
        
        for i in cluster_twice[label_sort[j]]:
            transformer = Transformer.from_crs("epsg:4326", "epsg:32650") 
            xt, yt = transformer.transform(user.trajs.stay_points[i].lat, user.trajs.stay_points[i].lng)
            x.append(xt)
            y.append(yt)
            z.append((user.trajs.stay_points[i].arv_t - user.trajs.stay_points[i].arv_t.replace(hour=0, minute=0, second=0, microsecond=0)).total_seconds() / 3600)
    
        ax.scatter(x, y, z, marker='^')


    print('')


    # np.save('time_interval_matrix_153.npy', time_interval_matrix)
    # np.save('distance_matrix_153.npy', distance_matrix)

    # distance_matrix = np.load('distance_matrix_153.npy')
    # time_interval_matrix = np.load('time_interval_matrix_153.npy')




    db = DBSCAN(eps=np.mean(time_interval) / 3600, metric='precomputed',
                min_samples=1, n_jobs=-1).fit(time_interval_matrix)
    labels = db.labels_

    n_clusters_ = len(set(labels)) - (1 if -1 in labels else 0)
    print('num cluster: %d' % (n_clusters_))

    # # plt.figure()
    # # plt.hist(labels, bins=n_clusters_)

    # print('num cluster: %d' % (n_clusters_))

    unique, counts = np.unique(labels, return_counts=True)
    max_label = np.argmax(counts)

    new_acts = []
    for i in range(point_num):
        # if True:
        if labels[i] == max_label:
            new_acts.append(user.trajs.stay_points[i])

    point_num = len(new_acts)
    distance_matrix = np.zeros((point_num, point_num))

    for i in range(point_num):
        for j in range(i + 1, point_num):
            distance_matrix[j][i] = distance_matrix[i][j] = utils.compute_dist(new_acts[i], new_acts[j])
    
    db = DBSCAN(eps=15, metric='precomputed', min_samples=1).fit(distance_matrix)
    labels = db.labels_
    n_clusters_ = len(set(labels)) - (1 if -1 in labels else 0)

    unique, counts = np.unique(labels, return_counts=True)
    max_label = np.argmax(counts)

    x = []
    y = []
    z = []

    for i in range(point_num):
        # if True:
        if labels[i] == max_label:
            transformer = Transformer.from_crs("epsg:4326", "epsg:32650") 
            xt, yt = transformer.transform(new_acts[i].lat, new_acts[i].lng)
            x.append(xt)
            y.append(yt)
            z.append((new_acts[i].arv_t - new_acts[i].arv_t.replace(hour=0, minute=0, second=0, microsecond=0)).total_seconds() / 3600)
    
    fig = plt.figure()
    ax = fig.add_subplot(111, projection='3d')
    ax.scatter(x, y, z, marker='o')

    print('')

    
    
time_interval.sort(reverse=True)

x = []
y = []
for activity in all_activity:
    if activity.lat > 39 and activity.lat < 41 and activity.lng > 116 and activity.lng < 117:
        x.append(activity.lng)
        y.append(activity.lat)

plt.figure()
plt.scatter(np.arange(len(time_interval)),
            time_interval[:], s=1, marker='o', facecolors='none', edgecolors='r')
plt.figure()
plt.scatter(x, y, s=1, marker='o', facecolors='none', edgecolors='r')
plt.show()
print('111')
